﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.ComponentModel;
using TA.DotNetUtils;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// Implements methods common across list controls. This class only exists because there is no MI in .NET. So, complain to MS.
	/// </summary>
	public static class ListControlCommon
	{
		/// <summary>
		/// Creates the list items by enumerating the specified data source and using the specified value, text and category fields to set properties of the created list items.
		/// </summary>
		public static void DataBind(IListControl baseListControl, object dataSource, string valueField, string textField, string categoryField)
		{
			IEnumerable list;
			if (dataSource is IListSource)
			{
				list = ((IListSource)dataSource).GetList();
			}
			else if (dataSource is IEnumerable)
				list = (IEnumerable)dataSource;
			else
				throw new ArgumentException("DataSource needs to be an IEnumerable or an IListSource (such as DataTable).", "dataSource");

			//Formatter valueFormatter = new Formatter(valueField, true),
			//  textFormatter = new Formatter(textField, true),
			//  categoryFormatter = new Formatter(categoryField, false);
			baseListControl.Items.Clear();
			baseListControl.AddFirstItems();
			Dictionary<string, ListItem> categories = new Dictionary<string, ListItem>();
			foreach (object o in list)
			{
				string category = string.IsNullOrEmpty(categoryField) ? "" : (o.Eval(categoryField) ?? "").ToString();// categoryFormatter.GetString(o);

				ListItem item = new ListItem
				{
					Value = (o.Eval(valueField) ?? o).ToString(),
					Text = (o.Eval(textField) ?? o).ToString(),
				};

				if (string.IsNullOrEmpty(category))
				{
					baseListControl.Items.Add(item);
				}
				else
				{
					if (!categories.ContainsKey(category))
					{
						ListItem cat = new ListItem
						{
							Text = category
						};
						foreach (ListItem catFirstItem in baseListControl.CategoryFirstItems)
							cat.Items.Add(catFirstItem);
						categories[category] = cat;
						baseListControl.Items.Add(cat);
					}

					categories[category].Items.Add(item);
				}
			}
		}
		/// <summary>
		/// Renders the list items contained within this control.
		/// </summary>
		/// <param name="baseListControl"></param>
		/// <param name="writer"></param>
		public static void RenderContents(IListControl baseListControl, System.Web.UI.HtmlTextWriter writer)
		{
			foreach (ListItem item in baseListControl.Items)
			{
				ListControlCommon.RenderItem(baseListControl, writer, item);
			}
		}
		/// <summary>
		/// Renders a list item.
		/// </summary>
		/// <param name="baseListControl"></param>
		/// <param name="writer"></param>
		/// <param name="item"></param>
		public static void RenderItem(IListControl baseListControl, System.Web.UI.HtmlTextWriter writer, ListItem item)
		{
			if (!item.Visible)
				return;

			ListControlCommon.AddItemAttributes(baseListControl, writer, item);
			if (item.Items.Count > 0)
			{
				baseListControl.RenderItemGroup(writer, item);
			}
			else
			{
				baseListControl.RenderItemOption(writer, item);
			}
		}
		/// <summary>
		/// Adds HTML attributes common to all list items.
		/// </summary>
		/// <param name="baseListControl"></param>
		/// <param name="writer"></param>
		/// <param name="item"></param>
		public static void AddItemAttributes(IListControl baseListControl, System.Web.UI.HtmlTextWriter writer, ListItem item)
		{
			if (!item.Enabled)
				writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");

			if (item.CssClass == null)
			{
				if (item.Items.Count == 0)
					item.CssClass = baseListControl.ItemCssClass;
				else
					item.CssClass = baseListControl.GroupCssClass;
			}

			item.Attributes.AddAttributes(writer);
		}
		/// <summary>
		/// Renders children of a grouped item.
		/// </summary>
		/// <param name="baseListControl"></param>
		/// <param name="writer"></param>
		/// <param name="group"></param>
		public static void RenderItemGroupChildren(IListControl baseListControl, HtmlTextWriter writer, ListItem group)
		{
			foreach (ListItem childItem in group.Items)
			{
				ListControlCommon.RenderItem(baseListControl, writer, childItem);
			}
		}

		/// <summary>
		/// Gets all options in this list control (no groups).
		/// </summary>
		public static ListItem[] GetOptions(IListControl baseListControl)
		{
			List<ListItem> res = new List<ListItem>();
			foreach (ListItem item in baseListControl.Items)
			{
				Options_AddItemRecursive(res, item);
			}

			return res.ToArray();
		}
		private static void Options_AddItemRecursive(List<ListItem> res, ListItem item)
		{
			if (item.Items.Count == 0)
				res.Add(item);
			else
			{
				foreach (ListItem itemChild in item.Items)
					Options_AddItemRecursive(res, itemChild);
			}
		}
		/// <summary>
		/// Props.
		/// </summary>
		public static readonly BasePropertyDefinition[] Properties = new BasePropertyDefinition[] {
			new ListJsonPropertyDefinition<ListItemCollection>("Items", "It", null) 
			{ 
				IsHTML = true,
			},
			new PropertyDefinition<string>("ItemCssClass", "IC", null),
			new PropertyDefinition<string>("GroupCssClass", "GC", null),
		};
		/// <summary>
		/// Adds the first items to the collection which always precede the data bound items.
		/// </summary>
		/// <param name="baseListControl"></param>
		public static void AddFirstItems(IListControl baseListControl)
		{
			foreach (ListItem li in baseListControl.FirstItems)
			{
				baseListControl.Items.Add(new ListItem(li));
			}
		}

		public static void RegisterIncludes(TControl listControl, IncludeCollection includes)
		{
			includes.Add(Script.Element_PerformRecursive);
			includes.Add(Script.Element_ClearChildNodes);
			includes.Add(Script.ListItem);
			includes.Add(new ScriptResourceInclude("TA.Turbo.Res.JS.ListControl.BaseListControl.js", typeof(BaseCommandControl)));
		}
	}
}
